See how denx software engineering compares to other vendors in security performance
A lack of signature verification in the bootloader of DENX Software Engineering Das U-Boot (U-Boot) v1.1.3 allows attackers to install crafted firmware files, leading to arbitrary code execution.
---------- Forwarded message --------- From: Eduardo' Vela" <Nava> <evn () google com> Date: Fri, 8 Jul 2022, 10:07 Subject: CVE-2022-2347 - Unchecked Download Size and Direction in U-Boot USB DFU To: <sultan.qasimkhan () nccgroup com>, 3pvd <3pvd () google com>, < u-boot () lists denx de>
Vendor: DENX Software Engineering Vendor URL: https://www.denx.de/wiki/U-Boot Versions affected: v2012.10-rc1 to <version of fix> Systems Affected: All systems with CONFIGDFUOVERUSB or CONFIGSPLDFU enabled Author: <Sultan Qasim Khan> <sultan.qasimkhan () nccgroup com> Advisory URL / CVE Identifier: CVE-2022-2347 Risk: 7.7 AV:P/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N
Summary
U-Boot is a popular and feature-rich bootloader for embedded systems. It includes optional support for the USB Device Firmware Update (DFU) protocol, which can be used by devices to download new firmware, or upload their current firmware.
The U-Boot DFU implementation does not bound the length field in USB DFU download setup packets, and it does not verify that the transfer direction corresponds to the specified command. Consequently, if a physical attacker crafts a USB DFU download setup packet with a wLength greater than 4096 bytes, they can write beyond the heap-allocated request buffer. It is also possible to read its content (and beyond it) if the direction bit for the setup packet indicates a device to host direction.
Location
drivers/usb/gadget/fdfu.c
Functions dfuhandle, statedfuidle, statedfudnloadidle, handlednload
Impact
Data beyond the heap-allocated req->buf buffer may be corrupted or read by a connected USB host when a device running U-Boot is in DFU mode. This may enable a malicious host to gain code execution on the device running U-Boot, or read sensitive data from the device.
Details
USB DFU setup packets are handled by the dfuhandle function. The DFU command is specified by the ctrl->bRequest field, and the transfer direction for the data phase is specified by the direction bit ctrl->bRequestType & USBDIRIN. The dfuhandle function calls state-specific handlers such as statedfuidle or statedfudnloadidle, and uses the value returned by the state handler as the length for the data phase of the transfer. The buffer that will be written to or read from in the data phase of the transfer is req->buf, which is heap allocated as 4096 (USBBUFSIZ) bytes in compositebind of drivers/usb/gadget/composite.c.
The request structure that is set up is then queued with the USB controller driver via a call to usbepqueue. There are several USB controllers supported by U-Boot, such as the popular Designware DWC2 whose support is implemented in <code>drivers/usb/gadget/dwc2udcotg.c </code>and <code>drivers/usb/gadget/dwc2udcotgxferdma.c</code>. These drivers are unaware of the allocated size for the request buffer (<code>req->buf</code>), and assume the supplied length field (<code>req- length</code>) is safe for the allocated buffer. static int dfuhandle(struct usbfunction f, const struct usbctrlrequest ctrl) { struct usbgadget gadget = f->config->cdev->gadget; struct usbrequest req = f->config->cdev->req; struct fdfu fdfu = f->config->cdev->req->context; …
if (reqtype == USBTYPESTANDARD) { … } else / DFU specific request / value = dfustate[fdfu->dfustate] (fdfu, ctrl, gadget, req);
if (value >= 0) { req->length = value; req->zero = value < len; value = usbepqueue(gadget->ep0, req, 0); if (value < 0) { debug("epqueue --> %d\n", value); req->status = 0; } }
return value; }
The DFU state handlers which support the download command (statedfuidle and statedfudnloadidle) return the value returned by handlednload when ctrl->bRequest is USBREQDFUDNLOAD. No checking of the transfer direction is performed; DFU download requests are assumed to always be OUT transfers (host to device). However, a malicious or compromised host could issue a download request setup packet with the USBDIRIN bit set (device to host). A DFU download request with the USBDIRIN bit set would cause data in req->buf to be sent to the host, rather than filling the buffer with data received from the host.
The handlednload function simply returns the length argument passed to it without any bounds checking. Both state handlers that call handlednload pass it the wLength field of the setup packet without any bounds checks. Consequently, a malicious host that sends a DFU setup packet with a length longer than 4096 bytes would result in a read or write beyond req->buf. The DFU functional descriptor does declare a maximum wTransferSize of DFUUSBBUFSIZ (4096 bytes), and compliant hosts would abide by not sending setup packets specifying lengths longer than this. However, a malicious or non-compliant host may send a DFU setup packet for a transfer longer than this.
static int handlednload(struct usbgadget gadget, u16 len) { struct usbcompositedev cdev = getgadgetdata(gad get); struct usbrequest req = cdev->req; struct fdfu fdfu = req->context;
if (len == 0) fdfu->dfustate = DFUSTATEdfuMANIFESTSYNC;
req->complete = dnloadrequestcomplete; return len; }
static int statedfuidle(struct fdfu fdfu, const struct usbctrlrequest ctrl, struct usbgadget gadget, struct usbrequest req) { u16 wvalue = le16tocpu(ctrl->wValue); u16 len = le16tocpu(ctrl->wLength); int value = 0;
switch (ctrl->bRequest) { case USBREQDFUDNLOAD: if (len == 0) { fdfu->dfustate = DFUSTATEdfuERROR; value = RETSTALL; break; } fdfu->dfustate = DFUSTATEdfuDNLOADSYNC; fdfu->blkseqnum = wvalue; value = handlednload(gadget, len); break; … }
return value; }
Recommendation
Limit USB transfer lengths to a maximum of DFUUSBBUFSIZ before adding them to the endpoint transfer queue in dfuhandle. In every DFU setup packet handler, also verify that the direction bit ctrl->bRequestType & USBDIRIN matches the request type (such as upload or download).
Vendor Communication
1. Feb 27 2022 - Initial email to security () denx de (this was the wrong email) 2. April 30 2022 - Follow up (60 days) 3. June 3 2022 - Email to wd () denx de (bounced but provided alternative contacts) 4. June 7 2022 - Discussion to post to the public mailing list 5. July 8 2022 - Public disclosure
Written by: Sultan Qasim Khan from NCC Group https://www.nccgroup.com/